package editor;

import editor.code.CodePanel;
import editor.code.LineRenderer;
import model.code.line.SimpleLine;
import util.IntList;
import widgets.CustomDialog;
import widgets.CustomPopup;

import java.awt.*;
import java.util.ArrayList;

/**
 * This class is for the popups that handle auto-completion.
 *
 * @author Neil Dickson
 */
public class AutoCompleteList extends CustomDialog {
	private String[]				content;
	private ArrayList<SimpleLine>	lines;
	private Image[]					images;
	private float[]					frequency;
	private String					currentlyTyped;
	private int						selected;
	private IntList					contentShown;

	public static final int			NUM_VISIBLE					= 11;
	public static final int			DEFAULT_HORIZONTAL_SPACE	= 5;
	public static final int			DEFAULT_VERTICAL_SPACE		= 2;

	public static final Color		SELECTED_COLOUR	= new Color(180,192,255);

	public AutoCompleteList(Container rootParent,ArrayList<SimpleLine> lines, Image[] images, float[] frequency, String currentlyTyped) {
		super(rootParent,false,DEFAULT_HORIZONTAL_SPACE,DEFAULT_VERTICAL_SPACE,6,6);
		this.lines = lines;
		content = new String[lines.size()];
		for (int i=0;i<content.length;++i) {
			content[i] = lines.get(i).toString();
		}
		this.images = images;
		this.frequency = frequency;
		contentShown = new IntList();
		setCurrentlyTyped(currentlyTyped,false);
	}

	public CustomPopup getPopup(Component owner,Point location) {
		return new CustomPopup(owner,this,location);
	}

	public IntList getContentShown() {
		return contentShown;
	}

	public void updateSize() {
		int width = 0;
		for (int i=0;i<contentShown.size();++i) {
			width = Math.max(width,lines.get(contentShown.get(i)).length()*CodePanel.FONT_WIDTH);
		}
		width += horizontalSpace+horizontalSpace+shadowSpacing;
		setSize(width,Math.min(NUM_VISIBLE,contentShown.size())*CodePanel.LINE_HEIGHT + verticalSpace+verticalSpace+shadowSpacing);
	}

	public void setCurrentlyTyped(String typed) {
		setCurrentlyTyped(typed,true);
	}
	public void setCurrentlyTyped(String typed,boolean updateVisibility) {
		currentlyTyped = typed;
		contentShown.clear();
		float maxFrequency = Float.NEGATIVE_INFINITY;
		for (int i=0;i<content.length;++i) {
			if (content[i].startsWith(typed)) {
				contentShown.add(i);
				if (frequency[i]>maxFrequency) {
					maxFrequency = frequency[i];
					selected = contentShown.size()-1;
				}
			}
		}
		if (!contentShown.isEmpty()) {
			if (!isVisible && updateVisibility) {
				setVisible(true);
			}
			updateSize();
		}
		else if (isVisible && updateVisibility) {
			setVisible(false);
		}
	}
	public String getCurentlyTyped() {
		return currentlyTyped;
	}
	public void selectedUp() {
		--selected;
		if (selected==-1) {
			selected = contentShown.size()-1;
		}
		repaint();
	}
	public void selectedDown() {
		++selected;
		if (selected==contentShown.size()) {
			selected = 0;
		}
		repaint();
	}
	public void selectedPageUp() {
		selected-=NUM_VISIBLE;
		if (selected<0) {
			selected = contentShown.size()+selected;
		}
		repaint();
	}
	public void selectedPageDown() {
		selected+=NUM_VISIBLE;
		if (selected>=contentShown.size()) {
			selected -= contentShown.size();
		}
		repaint();
	}

	/**
	 * Fills in more of currentlyTyped to the largest common beginning substring of all of the strings currently shown
	 * @return the new value of currentlyTyped
	 */
	public String fillIn() {
		if (contentShown.size()==0) {
			return "";
		}
		if (contentShown.size()==1) {
			currentlyTyped = content[contentShown.get(0)];
			return currentlyTyped;
		}
		int minStringSize = Integer.MAX_VALUE;	// This is an upper bound on the largest common beginning substring size
		for (int i=0;i<contentShown.size();++i) {
			if (content[contentShown.get(i)].length()<minStringSize) {
				minStringSize = content[contentShown.get(i)].length();
			}
		}
		int sizeCommon = 0;
		String first = content[contentShown.get(0)];
		String second = content[contentShown.get(1)];
		while (sizeCommon<minStringSize && first.substring(sizeCommon,sizeCommon+1).equalsIgnoreCase(second.substring(sizeCommon,sizeCommon+1))) {
			++sizeCommon;
		}
		for (int i=2;i<contentShown.size();++i) {
			int tempSize = 0;
			second = content[contentShown.get(i)];
			while (tempSize<sizeCommon && first.substring(tempSize,tempSize+1).equalsIgnoreCase(second.substring(tempSize,tempSize+1))) {
				++tempSize;
			}
			if (tempSize<sizeCommon) {
				sizeCommon = tempSize;
			}
		}
		currentlyTyped = first.substring(0,sizeCommon);
		return currentlyTyped;
	}

	public String getSelected() {
		return content[contentShown.get(selected)];
	}

	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		int width = getWidth()-horizontalSpace-horizontalSpace-shadowSpacing;
		Rectangle bounds = new Rectangle(horizontalSpace,verticalSpace,width,CodePanel.LINE_HEIGHT);
		if (selected<NUM_VISIBLE/2 || contentShown.size()<NUM_VISIBLE) {
			g.setColor(SELECTED_COLOUR);
			g.fillRect(bounds.x,bounds.y + selected*CodePanel.LINE_HEIGHT,bounds.width,bounds.height);
			for (int i=0;i<contentShown.size() && i<NUM_VISIBLE;++i) {
				LineRenderer.draw(lines.get(contentShown.get(i)),g,bounds);
				bounds.y += CodePanel.LINE_HEIGHT;
			}
		}
		else if (selected>=contentShown.size()-(NUM_VISIBLE/2)) {
			g.setColor(SELECTED_COLOUR);
			g.fillRect(bounds.x,bounds.y + (selected-(contentShown.size()-NUM_VISIBLE))*CodePanel.LINE_HEIGHT,bounds.width,bounds.height);
			for (int i=contentShown.size()-NUM_VISIBLE;i<contentShown.size();++i) {
				LineRenderer.draw(lines.get(contentShown.get(i)),g,bounds);
				bounds.y += CodePanel.LINE_HEIGHT;
			}
		}
		else {
			g.setColor(SELECTED_COLOUR);
			g.fillRect(bounds.x,bounds.y + NUM_VISIBLE/2*CodePanel.LINE_HEIGHT,bounds.width,bounds.height);
			for (int i=selected-NUM_VISIBLE/2;i<=selected+NUM_VISIBLE/2;++i) {
				LineRenderer.draw(lines.get(contentShown.get(i)),g,bounds);
				bounds.y += CodePanel.LINE_HEIGHT;
			}
		}
	}
}
